package com.example.teesystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.teesystem.common.utils.*;
import com.example.teesystem.entity.*;
import com.example.teesystem.entity.Class;
import com.example.teesystem.entity.vo.PageRequestVo;
import com.example.teesystem.entity.vo.PageResponseVo;
import com.example.teesystem.entity.vo.exam.ExamUpdateVo;
import com.example.teesystem.entity.vo.examEvaluation.EvaluationUpdateVo;
import com.example.teesystem.entity.vo.examEvaluation.ExamEvaluationInsertVo;
import com.example.teesystem.entity.vo.examPaper.*;
import com.example.teesystem.entity.vo.preCourseScore.PreCourseResponse;
import com.example.teesystem.entityDto.*;
import com.example.teesystem.filter.MyHandlerInterceptor;
import com.example.teesystem.mapper.*;
import com.example.teesystem.service.*;
import lombok.RequiredArgsConstructor;
import org.apache.tomcat.util.buf.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author NieYaShi
 * @description 针对表【t_exam_paper】的数据库操作Service实现
 * @createDate 2022-04-11 09:14:07
 */
@Service
@RequiredArgsConstructor
public class ExamPaperServiceImpl extends ServiceImpl<ExamPaperMapper, ExamPaper>
        implements ExamPaperService {

    private final ClassMapper classMapper;
    private final ClassStudentMapper classStudentMapper;
    private final CourseMapper courseMapper;
    private final IssueMapper issueMapper;
    private final ExamPaperMapper examPaperMapper;
    private final ExamIssueMapper examIssueMapper;
    private final ExamMapper examMapper;
    private final ExamEvaluationMapper examEvaluationMapper;
    private final ExamService examService;
    private final IssueRecordService issueRecordService;
    private final PreCourseScoreService preCourseScoreService;
    private final UserMapper userMapper;

    private static final int ERROR = -1;

    @Override
    public Response addExamPaper(ExamPaperInsertVo examPaperInsertVo) {
        ExamPaper examPaper = new ExamPaper();
        BeanUtils.copyProperties(examPaperInsertVo, examPaper);
        examPaper.setTeacherId(MyHandlerInterceptor.getUid());
        examPaper.setName(examPaperInsertVo.getName());

        int id = ERROR;
        examPaperMapper.insert(examPaper);
        id = examPaper.getId();
        if (id == ERROR) {
            return Response.error(ResultCode.INSERT_ERROR);
        } else {
            Map<String,Integer> map = new HashMap<>();
            map.put("paperId",id);
            return Response.ok(map);
        }
    }

    @Override
    public Response getExamPaperList(ExamPaperSelectVo examPaperSelectVo) {
        List<ExamPaperList> examPaperLists = new ArrayList<>();
        List<Integer> examPaperIds = new ArrayList<>();
        if (examPaperSelectVo.getClassId() != null) {
            String classIdRegexp = getClassRegex(examPaperSelectVo.getClassId());
            examPaperIds.addAll(examPaperMapper.getPaperIdByClassId(classIdRegexp));

            if (examPaperIds.size() == 0){
                return Response.ok(new PageResponseVo<>(examPaperLists, examPaperSelectVo.getCur(), examPaperSelectVo.getSize(), 1));
            }
        }

        Page<ExamPaper> page = new Page<>(examPaperSelectVo.getCur(), examPaperSelectVo.getSize());
        QueryWrapper<ExamPaper> wrapper = new QueryWrapper<>();
        wrapper.eq("course_id", examPaperSelectVo.getCourseId())
                .in(examPaperSelectVo.getClassId() != null, "id", examPaperIds)
                .orderByDesc("id");

        Page<ExamPaper> myPage = this.page(page, wrapper);
        List<ExamPaper> examPapers = myPage.getRecords();

        for (ExamPaper examPaper : examPapers) {
            ExamPaperList examPaperList = new ExamPaperList(examPaper);
            examPaperLists.add(examPaperList);
        }

        return Response.ok(new PageResponseVo<>(examPaperLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages()));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Response releaseExamPaper(Integer paperId) {
        ExamPaper check = examPaperMapper.selectById(paperId);
        if (check == null) {
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }

        if(check.getIsFinish() == 1) {
            return Response.error(ResultCode.EXAM_PAPER_IS_FINISHED);
        }
        if(check.getIsMark() == 1) {
            return Response.error(ResultCode.EXAM_PAPER_IS_MARKED);
        }

        List<String> classIdList = new ArrayList<>();
        // 检查发布考试的班级所属课程和试卷的课程是否一致
        List<Integer> errorExamClass = new ArrayList<>();

        List<ExamIssue> examIssueList = examIssueMapper.getExamIssueByPaperId(paperId);
        if (examIssueList.size() == 0){
            return Response.error(ResultCode.EXAM_NOT_HAVE_ISSUE_ERROR);
        }
        // 检查试卷试题是否都设置分值
        List<Integer> noScoreIssueIds = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            if (examIssue.getScore() == 0) {
                noScoreIssueIds.add(examIssue.getIssueId());
            }
        }

        if (noScoreIssueIds.size() == 0) {
            String classes = StringUtils.join(classIdList, '$');
            examPaperMapper.releaseExamPaper(paperId);
            return Response.ok();
        } else {
            return Response.error(ResultCode.EXIST_NO_SCORE_ISSUE, noScoreIssueIds);
        }
    }

    @Override
    public Response getRandomIssue(IntelligentPaperCreateVo intelligentPaperCreateVo) {
        List<Issue> issues = new ArrayList<>();
        List<Issue> paperIssue = new ArrayList<>();
        List<IssueSimpleMessage> issueSimpleMessages = new ArrayList<>();
        Integer[] chapterList = intelligentPaperCreateVo.getChapter();
        double wave = 0.5;

        int start = TimeUtil.getSecondTimestamp();//算法开始时间
        int end;//算法结束时间
        int timeOut = 10;

        StringBuilder issueType = new StringBuilder();

        /**
         * 判断
         */
        if (intelligentPaperCreateVo.getJudge() != 0 && intelligentPaperCreateVo.getJudge()!=null) {
            issueType.append(IssueUtil.JUDGE).append("$");
            Map<Integer, Integer> map = RandomUtil.getChapterIssue(intelligentPaperCreateVo.getJudge(), chapterList);
            float difficulty = 0;
            start = TimeUtil.getSecondTimestamp();
            while (difficulty > intelligentPaperCreateVo.getLevel() + wave || difficulty < intelligentPaperCreateVo.getLevel() - wave) {
                difficulty = 0;
                issues.clear();
                for (Integer integer : chapterList) {
                    int n = map.getOrDefault(integer, 0);
                    if (n == 0) {
                        continue;
                    }
                    issues.addAll(issueMapper.getRandomIssue(intelligentPaperCreateVo.getCourseId(), integer, IssueUtil.JUDGE, map.getOrDefault(integer, 0)));
                }
                for (Issue issue : issues) {
                    difficulty = difficulty + issue.getDifficulty();
                }
                end = TimeUtil.getSecondTimestamp();
                if (end - start > timeOut) {
                    return Response.error(ResultCode.PAPER_TIME_OUT.getMsg(), ResultCode.PAPER_TIME_OUT.getCode());
                }
                difficulty = difficulty / (intelligentPaperCreateVo.getJudge());
            }
            paperIssue.addAll(issues);
            issues.clear();
        }

        /**
         * 填空
         */
        if (intelligentPaperCreateVo.getFillBlank() != 0 && intelligentPaperCreateVo.getFillBlank() != null) {
            issueType.append(IssueUtil.FILL_IN_THE_BLANKS).append("$");
            Map<Integer, Integer> map = RandomUtil.getChapterIssue(intelligentPaperCreateVo.getFillBlank(), chapterList);
            float difficulty = 0;
            start = TimeUtil.getSecondTimestamp();
            while (difficulty > intelligentPaperCreateVo.getLevel() + wave || difficulty < intelligentPaperCreateVo.getLevel() - wave) {
                difficulty = 0;
                issues.clear();
                for (Integer integer : chapterList) {
                    int n = map.getOrDefault(integer, 0);
                    if (n == 0) {
                        continue;
                    }
                    issues.addAll(issueMapper.getRandomIssue(intelligentPaperCreateVo.getCourseId(), integer, IssueUtil.FILL_IN_THE_BLANKS, n));
                }
                for (Issue issue : issues) {
                    difficulty = difficulty + issue.getDifficulty();
                }
                end = TimeUtil.getSecondTimestamp();
                if (end - start > timeOut) {
                    return Response.error(ResultCode.PAPER_TIME_OUT.getMsg(), ResultCode.PAPER_TIME_OUT.getCode());
                }
                difficulty = difficulty / (intelligentPaperCreateVo.getFillBlank());
            }
            paperIssue.addAll(issues);
            issues.clear();
        }

        /**
         * 单选
         */
        if (intelligentPaperCreateVo.getSingle() != 0 && intelligentPaperCreateVo.getSingle() != null) {
            issueType.append(IssueUtil.SINGLE_CHOICE).append("$");
            Map<Integer, Integer> map = RandomUtil.getChapterIssue(intelligentPaperCreateVo.getSingle(), chapterList);
            float difficulty = 0;
            start = TimeUtil.getSecondTimestamp();
            while (difficulty > intelligentPaperCreateVo.getLevel() + wave || difficulty < intelligentPaperCreateVo.getLevel() - wave) {
                difficulty = 0;
                issues.clear();
                for (Integer integer : chapterList) {
                    int n = map.getOrDefault(integer, 0);
                    if (n == 0) {
                        continue;
                    }
                    issues.addAll(issueMapper.getRandomIssue(intelligentPaperCreateVo.getCourseId(), integer, IssueUtil.SINGLE_CHOICE, n));
                }
                for (Issue issue : issues) {
                    difficulty = difficulty + issue.getDifficulty();
                }
                end = TimeUtil.getSecondTimestamp();
                if (end - start > timeOut) {
                    return Response.error(ResultCode.PAPER_TIME_OUT.getMsg(), ResultCode.PAPER_TIME_OUT.getCode());
                }
                difficulty = difficulty / (intelligentPaperCreateVo.getSingle());
            }
            paperIssue.addAll(issues);
            issues.clear();
        }

        /**
         * 多选
         */
        if (intelligentPaperCreateVo.getMultiple() != 0 && intelligentPaperCreateVo.getMultiple()!=null) {
            issueType.append(IssueUtil.MULTIPLE_CHOICE).append("$");
            Map<Integer, Integer> map = RandomUtil.getChapterIssue(intelligentPaperCreateVo.getMultiple(), chapterList);
            float difficulty = 0;
            start = TimeUtil.getSecondTimestamp();
            while (difficulty > intelligentPaperCreateVo.getLevel() + wave || difficulty < intelligentPaperCreateVo.getLevel() - wave) {
                difficulty = 0;
                issues.clear();
                for (Integer integer : chapterList) {
                    int n = map.getOrDefault(integer, 0);
                    if (n == 0) {
                        continue;
                    }
                    issues.addAll(issueMapper.getRandomIssue(intelligentPaperCreateVo.getCourseId(), integer, IssueUtil.MULTIPLE_CHOICE, n));
                    System.out.println(issues);
                }
                for (Issue issue : issues) {
                    difficulty = difficulty + issue.getDifficulty();
                }
                end = TimeUtil.getSecondTimestamp();
                if (end - start > timeOut) {
                    return Response.error(ResultCode.PAPER_TIME_OUT.getMsg(), ResultCode.PAPER_TIME_OUT.getCode());
                }
                difficulty = difficulty / (intelligentPaperCreateVo.getMultiple());
            }
            paperIssue.addAll(issues);
            issues.clear();
        }

        /**
         * 简答
         */
        if (intelligentPaperCreateVo.getBriefAnswer() != 0 && intelligentPaperCreateVo.getBriefAnswer() != null) {
            issueType.append(IssueUtil.BRIEF_ANSWER).append("$");
            Map<Integer, Integer> map = RandomUtil.getChapterIssue(intelligentPaperCreateVo.getBriefAnswer(), chapterList);
            float difficulty = 0;
            start = TimeUtil.getSecondTimestamp();
            while (difficulty > intelligentPaperCreateVo.getLevel() + wave || difficulty < intelligentPaperCreateVo.getLevel() - wave) {
                difficulty = 0;
                issues.clear();
                for (Integer integer : chapterList) {
                    int n = map.getOrDefault(integer, 0);
                    if (n == 0) {
                        continue;
                    }
                    issues.addAll(issueMapper.getRandomIssue(intelligentPaperCreateVo.getCourseId(), integer, IssueUtil.BRIEF_ANSWER, n));
                }
                for (Issue issue : issues) {
                    difficulty = difficulty + issue.getDifficulty();
                }
                end = TimeUtil.getSecondTimestamp();
                if (end - start > timeOut) {
                    return Response.error(ResultCode.PAPER_TIME_OUT.getMsg(), ResultCode.PAPER_TIME_OUT.getCode());
                }
                difficulty = difficulty / (intelligentPaperCreateVo.getBriefAnswer());
            }
            paperIssue.addAll(issues);
            issues.clear();
        }

        ExamPaper examPaper = new ExamPaper();
        examPaper.setName(intelligentPaperCreateVo.getName());
        examPaper.setCourseId(intelligentPaperCreateVo.getCourseId());
        examPaper.setLevel(intelligentPaperCreateVo.getLevel());
        examPaper.setTeacherId(MyHandlerInterceptor.getUid());
        examPaper.setIncludeIssueType(issueType.toString());

        int id=1;
        examPaperMapper.insert(examPaper);
        id = examPaper.getId();
        if (id == ERROR) {
            return Response.error(ResultCode.INSERT_ERROR);
        } else {
            for (Issue issue : paperIssue) {
                issueSimpleMessages.add(new IssueSimpleMessage(issue));
                ExamIssue examIssue = new ExamIssue();
                examIssue.setPaperId(id);
                examIssue.setIssueId(issue.getId());
                issueMapper.addReferenceNum(issue.getId());
                examIssueMapper.insert(examIssue);
            }
            paperIssue.clear();
        }
        Map<String,Integer> result = new HashMap<>();
        result.put("paperId",id);
        return Response.ok(result);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Response deleteExamPaper(Integer id) {
        ExamPaper check = examPaperMapper.selectById(id);
        if (check == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }
        if (check.getIsPublish() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_PUBLISHED);
        }
        if (check.getIsFinish() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_FINISHED);
        }
        if (check.getIsMark() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_MARKED);
        }
        try {
            examPaperMapper.deleteExamPaper(id);
            return Response.ok();
        } catch (Exception e) {
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR);
        }
    }

    @Override
    public Response updateExamPaper(ExamPaperUpdateVo1 examPaperUpdateVo1) {
        ExamPaper check = examPaperMapper.selectById(examPaperUpdateVo1.getId());
        if (check == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }
        if (check.getIsPublish() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_PUBLISHED);
        }
        if (check.getIsFinish() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_FINISHED);
        }
        if (check.getIsMark() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_MARKED);
        }

        ExamPaper examPaper = new ExamPaper();
        BeanUtils.copyProperties(check, examPaper);
        if (examPaperUpdateVo1.getName() != null && !examPaperUpdateVo1.getName().equals("")) {
            String newName = examPaperUpdateVo1.getName();
            examPaper.setName(newName);
        }
        if (examPaperUpdateVo1.getStartTime() != null) {
            examPaper.setStartTime(examPaperUpdateVo1.getStartTime());
        }
        if (examPaperUpdateVo1.getEndTime() != null) {
            examPaper.setEndTime(examPaperUpdateVo1.getEndTime());
        }
        if (examPaperUpdateVo1.getClasses() != null){
            StringBuilder classes = new StringBuilder();
            for(int i = 0; i < examPaperUpdateVo1.getClasses().length; i++){
                classes.append(examPaperUpdateVo1.getClasses()[i]).append("$");
            }
            classes.deleteCharAt(classes.lastIndexOf("$"));
            examPaper.setClasses(classes.toString());
        }
        examPaperMapper.updateById(examPaper);

        return Response.ok();
    }

    @Override
    public Response undoExamPaper(Integer id) {
        ExamPaper check = examPaperMapper.selectById(id);
        if (check == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }
        if (check.getIsFinish() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_FINISHED);
        }
        if (check.getIsMark() == 1){
            return Response.error(ResultCode.EXAM_PAPER_IS_MARKED);
        }
        if (check.getIsPublish() != 0) {
            examPaperMapper.undoExamPaper(id);
        }
        return Response.ok();
    }

    @Override
    public Response previewExamPaper(Integer id) {
        ExamPaper examPaper = examPaperMapper.selectById(id);
        if (examPaper == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }

        ExamPaperMessage examPaperMessage = new ExamPaperMessage(examPaper);
        Integer score = examIssueMapper.getTotalScore(id) == null ? 0 : examIssueMapper.getTotalScore(id);

        examPaperMessage.setScore(score);
        //修改试卷分值
        examPaperMapper.updateExamPaperScore(id, score);

        List<ExamIssue> result = examIssueMapper.getExamIssueByPaperId(id);
        //刚创建完试卷进行预览（没有题目）
        if (result.size() == 0){
            return Response.ok(examPaperMessage);
        }

        List<Integer> ids = new ArrayList<>();
        for (ExamIssue examIssue : result) {
            ids.add(examIssue.getIssueId());
        }
        List<Issue> issueList = issueMapper.getIssuesByIds(ids);
        //题目分类
        Map<Integer, List<Issue>> map = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        Map<String, List<ExamIssueList>> listMap = new HashMap<>();

        for (Map.Entry<Integer, List<Issue>> entry : map.entrySet()) {
            Integer mapKey = entry.getKey();
            List<Issue> mapValue = entry.getValue();
            List<ExamIssueList> examIssueLists = new ArrayList<>();

            for (Issue issue : mapValue) {
                ExamIssueList examIssueList = new ExamIssueList(getExamIssue(result, issue.getId()));
                examIssueList.setIssueSimpleMessage(new IssueSimpleMessage(issue));
                examIssueLists.add(examIssueList);
            }

            listMap.put(IssueUtil.getIssueTypeName(mapKey), examIssueLists);
        }

        examPaperMessage.setListMap(listMap);

        List<Class> classList = new ArrayList<>();

        if(examPaper.getClasses()!= null && !examPaper.getClasses().equals("")){
            String []classes = examPaper.getClasses().split("\\$");
            for (String aClass : classes) {
                examPaperMessage.getClassList().add(classMapper.getClassById(Integer.parseInt(aClass)));
            }
        }
        return Response.ok(examPaperMessage);
    }

    private ExamIssue getExamIssue(List<ExamIssue> examIssues, Integer issueId) {
        for (ExamIssue examIssue : examIssues) {
            if (examIssue.getIssueId().equals(issueId)) {
                return examIssue;
            }
        }
        return new ExamIssue();
    }

    @Override
    public Response finishMarkSingleStudentPaper(ExamEvaluationInsertVo examEvaluationInsertVo) {
        List<Exam> examList = examMapper.getExamsByPaperIdAndStudentId(examEvaluationInsertVo.getPaperId(), examEvaluationInsertVo.getStudentId());
        List<Exam> examsNotMark = examMapper.check(examEvaluationInsertVo.getPaperId(), examEvaluationInsertVo.getStudentId());
        if(examsNotMark!=null&&examsNotMark.size()!=0){
            return Response.error(ResultCode.EXAM_NOTMARK);
        }

        if (examList.size() == 0){
            return Response.error(ResultCode.STUDENT_NOT_ANSWER_ERROR);
        }

        int score = examMapper.summaryScore(examEvaluationInsertVo.getPaperId(), examEvaluationInsertVo.getStudentId());

        ExamEvaluation check = examEvaluationMapper.getEvaluationByPaperAndUserId(examEvaluationInsertVo.getPaperId(), examEvaluationInsertVo.getStudentId());
        if (check == null) {
            ExamEvaluation examEvaluation = new ExamEvaluation();
            BeanUtils.copyProperties(examEvaluationInsertVo, examEvaluation);
            examEvaluation.setMessage(examEvaluationInsertVo.getMessage() == null ? "" : examEvaluationInsertVo.getMessage());
            examEvaluation.setScore(score);
            examEvaluation.setIsMark(1);

            int id = ERROR;
            examEvaluationMapper.insert(examEvaluation);
            id = examEvaluation.getId();
            if (id == ERROR) {
                return Response.error(ResultCode.INSERT_ERROR);
            }
        } else {
            check.setScore(score);
            check.setMessage(examEvaluationInsertVo.getMessage() == null ? "" : examEvaluationInsertVo.getMessage());
            check.setIsMark(1);
            examEvaluationMapper.updateById(check);
        }

        //检查试卷是否全部完成阅卷
        ExamPaper examPaper = examPaperMapper.selectById(examEvaluationInsertVo.getPaperId());
        checkIsFinishMarkPaper(examPaper);

        return Response.ok();
    }


    private void checkIsFinishMarkPaper(ExamPaper examPaper) {
        String[] classIds = examPaper.getClasses().trim().split("\\$");

        List<Integer> studentIds = new ArrayList<>();
        for (String classId : classIds) {
            studentIds.addAll(classStudentMapper.getStudentIdByClassId(Integer.parseInt(classId)));
        }

        List<Integer> markedStudentIds = examEvaluationMapper.getMarkedStudentIdByPaperId(examPaper.getId(), studentIds);

        if (markedStudentIds.size() == studentIds.size()) {
            examPaper.setIsMark(1);
            examPaperMapper.updateById(examPaper);
        }
    }

    @Override
    public Response getMarkedPaperMessage(Integer paperId, Integer studentId) {
        ExamPaper examPaper = examPaperMapper.selectById(paperId);
        if (examPaper == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }

        QueryWrapper<ExamIssue> examIssueQueryWrapper = new QueryWrapper<>();
        examIssueQueryWrapper
                .eq("paper_id", paperId)
                .orderByAsc("issue_id");
        List<ExamIssue> examIssueList = examIssueMapper.selectList(examIssueQueryWrapper);
        if (examIssueList.size() == 0){
            return Response.ok();
        }

        QueryWrapper<Exam> examQueryWrapper = new QueryWrapper<>();
        examQueryWrapper
                .eq("paper_id", paperId)
                .eq("student_id", studentId)
                .orderByAsc("issue_id");
        List<Exam> examList = examMapper.selectList(examQueryWrapper);
        if (examList.size() == 0){
            return Response.error(ResultCode.STUDENT_NOT_ANSWER_ERROR);
        }

        List<Integer> ids = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            ids.add(examIssue.getIssueId());
        }
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .in("id", ids)
                .orderByAsc("id");
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);

        ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(paperId, studentId);
        if (examEvaluation == null){
            return Response.error(ResultCode.EXAM_NOT_FINISH_MARK_ERROR);
        }

        List<MarkedIssueMessage> markedIssueMessages = new ArrayList<>();
        for (int i = 0; i < examIssueList.size(); i++) {
            markedIssueMessages.add(new MarkedIssueMessage(issueList.get(i), examList.get(i), examIssueList.get(i)));
        }
        Map<Integer, List<MarkedIssueMessage>> map = markedIssueMessages.stream().collect(Collectors.groupingBy(
                MarkedIssueMessage::getType));

        Map<String, List<MarkedIssueMessage>> listMap = new HashMap<>();
        for (Integer key : map.keySet()) {
            listMap.put(IssueUtil.getIssueTypeName(key), map.get(key));
        }

        MarkedPaperMessage markedPaperMessage = new MarkedPaperMessage(studentId, examPaper, examEvaluation);
        markedPaperMessage.setListMap(listMap);
        return Response.ok(markedPaperMessage);
    }

    @Override
    public Response updateMarkedIssue(ExamUpdateVo examUpdateVo) {
        ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(examUpdateVo.getPaperId(), examUpdateVo.getStudentId());
        if (examEvaluation != null) {
            if (examEvaluation.getIsPublish() == 0) {
                Exam exam = examMapper.getExamByPaperIssueAndStudentId(examUpdateVo.getPaperId(), examUpdateVo.getIssueId(), examUpdateVo.getStudentId());
                if (exam == null) {
                    return Response.error(ResultCode.EXAM_ISSUE_NOT_EXIST_ERROR);
                }
                exam.setScore(examUpdateVo.getScore());
                exam.setMessage(examUpdateVo.getMessage());
                examMapper.updateById(exam);

                //修改总分
                int score = examMapper.summaryScore(examUpdateVo.getPaperId(), examUpdateVo.getStudentId());
                examEvaluation.setScore(score);
                examEvaluationMapper.updateById(examEvaluation);

                return Response.ok();
            } else {
                return Response.error(ResultCode.EXAM_PAPER_PUBLISHED_ERROR);
            }
        } else {
            return Response.error(ResultCode.EXAM_NOT_FINISH_MARK_ERROR);
        }
    }

    @Override
    public Response studentGetExamList(PageRequestVo pageRequestVo) {
        List<Integer> classIds = classStudentMapper.getClassIdByStudentId(MyHandlerInterceptor.getUid());

        List<ExamPaperList> examPaperLists = new ArrayList<>();

        List<Integer> examPaperIds = new ArrayList<>();
        for (Integer classId : classIds) {
            String classIdRegexp = getClassRegex(classId);
            examPaperIds.addAll(examPaperMapper.getExaminationPaperIds(classIdRegexp));
        }
        if (examPaperIds.size() == 0){
            return Response.ok(new PageResponseVo<>(examPaperLists, pageRequestVo.getCur(), pageRequestVo.getSize(), 1));
        }

        List<Integer> completedPaperIds = examEvaluationMapper.getExamedPaperIds(MyHandlerInterceptor.getUid());

        List<Integer> notExamPaperIds = listRemove(examPaperIds, completedPaperIds);

        if (notExamPaperIds.size() == 0){
            return Response.ok(new PageResponseVo<>(examPaperLists, pageRequestVo.getCur(), pageRequestVo.getSize(), 1));
        }

        Page<ExamPaper> page = new Page<>(pageRequestVo.getCur(), pageRequestVo.getSize());
        QueryWrapper<ExamPaper> wrapper = new QueryWrapper<>();
        wrapper.in("id", notExamPaperIds)
                .orderByDesc("id");
        Page<ExamPaper> myPage = this.page(page, wrapper);
        List<ExamPaper> examPaperList = myPage.getRecords();

        for (ExamPaper examPaper : examPaperList) {
            ExamPaperList paperList = new ExamPaperList(examPaper);
            examPaperLists.add(paperList);
        }

        PageResponseVo<ExamPaperList> pageResponseVo = new PageResponseVo<>(examPaperLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages());
        return Response.ok(pageResponseVo);
    }

    private List<Integer> listRemove(List<Integer> listA, List<Integer> listB){
        HashSet<Integer> hs1 = new HashSet<>(listA);
        HashSet<Integer> hs2 = new HashSet<>(listB);
        hs1.removeAll(hs2);
        List<Integer> listC = new ArrayList<>(hs1);
        return listC;
    }

    private String getClassRegex(int classId){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("^");
        stringBuilder.append(classId);
        stringBuilder.append("$|^");
        stringBuilder.append(classId);
        stringBuilder.append("\\$|\\$");
        stringBuilder.append(classId);
        stringBuilder.append("\\$|\\$");
        stringBuilder.append(classId);
        stringBuilder.append("$");
        return stringBuilder.toString();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Response publishMarkedPaper(Integer classId, Integer paperId) {
        ExamPaper check = examPaperMapper.selectById(paperId);
        if (check == null) {
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }
        if (check.getIsPublish() == 0) {
            return Response.error(ResultCode.EXAM_NOT_PUBLISH_ERROR);
        }
        if (check.getIsFinish() == 0) {
            return Response.error(ResultCode.EXAM_NOT_FINISH_ERROR);
        }

        String[] classIds = check.getClasses().trim().split("\\$");
        for (String id : classIds) {
            if (classId.equals(Integer.parseInt(id))) {
                List<Integer> studentIds = classStudentMapper.getStudentIdByClassId(classId);

                List<Integer> markedStudentIds = examEvaluationMapper.getMarkedStudentIdByPaperId(paperId, studentIds);

                if (studentIds.size() > markedStudentIds.size()) {
                    List<Integer> differentIds = getDifferent(studentIds, markedStudentIds);
                    return Response.error(ResultCode.STUDENT_NOT_MARK_ERROR, differentIds);
                }

                for (Integer studentId : studentIds) {
                    examEvaluationMapper.publishMarkedPaper(paperId, studentId);
                }
                return Response.ok();
            }
        }
        return Response.error(ResultCode.CLASS_EXAM_NOT_EXIST);

    }

    private List<Integer> getDifferent(List<Integer> list1, List<Integer> list2) {
        Map<Integer, Integer> map = new HashMap<>(list1.size() + list2.size());
        List<Integer> diff = new ArrayList<>();
        List<Integer> maxList = list1;
        List<Integer> minList = list2;
        if (list2.size() > list1.size()) {
            maxList = list2;
            minList = list1;
        }

        for (Integer string : maxList) {
            map.put(string, 1);
        }

        for (Integer string : minList) {
            Integer cc = map.get(string);
            if (cc != null) {
                map.put(string, ++cc);
                continue;
            }
            map.put(string, 1);
        }

        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() == 1) {
                diff.add(entry.getKey());
            }
        }
        return diff;
    }

    @Override
    public Response saveUnMarkedPaper(ExamEvaluationInsertVo examEvaluationInsertVo) {
        int paperId = examEvaluationInsertVo.getPaperId(),studentId = examEvaluationInsertVo.getStudentId();
        ExamEvaluation check = examEvaluationMapper.getEvaluationByPaperAndUserId(paperId, studentId);

        int score = examMapper.summaryScore(paperId, studentId);

        if (check == null) {
            ExamEvaluation examEvaluation = new ExamEvaluation();
            examEvaluation.setPaperId(paperId);
            examEvaluation.setStudentId(studentId);
            examEvaluation.setScore(score);
            examEvaluation.setMessage(examEvaluationInsertVo.getMessage());
            int id = ERROR;
            examEvaluationMapper.insert(examEvaluation);
            id = examEvaluation.getId();
            if (id == ERROR) {
                return Response.error(ResultCode.INSERT_ERROR);
            }
        } else {
            check.setScore(score);
            check.setMessage(examEvaluationInsertVo.getMessage());
            examEvaluationMapper.updateById(check);
        }
        return Response.ok();
    }

    @Override
    public Response studentGetMarkedPaperMessage(Integer paperId) {
        ExamPaper examPaper = examPaperMapper.selectById(paperId);
        if (examPaper == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }

        QueryWrapper<ExamIssue> examIssueQueryWrapper = new QueryWrapper<>();
        examIssueQueryWrapper
                .eq("paper_id", paperId)
                .orderByAsc("issue_id");
        List<ExamIssue> examIssueList = examIssueMapper.selectList(examIssueQueryWrapper);
        if (examIssueList.size() == 0){
            return Response.ok();
        }

        QueryWrapper<Exam> examQueryWrapper = new QueryWrapper<>();
        examQueryWrapper
                .eq("paper_id", paperId)
                .eq("student_id", MyHandlerInterceptor.getUid())
                .orderByAsc("issue_id");
        List<Exam> examList = examMapper.selectList(examQueryWrapper);
        if (examList.size() == 0){
            return Response.ok();
        }

        List<Integer> ids = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            ids.add(examIssue.getIssueId());
        }

        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .in("id", ids)
                .orderByAsc("id");
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);

        ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(paperId, MyHandlerInterceptor.getUid());
        if (examEvaluation == null){
            return Response.ok();
        }

        List<MarkedIssueMessage> markedIssueMessages = new ArrayList<>();
        for (int i = 0; i < examIssueList.size(); i++) {
            markedIssueMessages.add(new MarkedIssueMessage(issueList.get(i), examList.get(i), examIssueList.get(i)));
        }
        Map<Integer, List<MarkedIssueMessage>> map = markedIssueMessages.stream().collect(Collectors.groupingBy(
                MarkedIssueMessage::getType));

        Map<String, List<MarkedIssueMessage>> listMap = new HashMap<>();
        for (Integer key : map.keySet()) {
            listMap.put(IssueUtil.getIssueTypeName(key), map.get(key));
        }

        MarkedPaperMessage markedPaperMessage = new MarkedPaperMessage(MyHandlerInterceptor.getUid(), examPaper, examEvaluation);
        markedPaperMessage.setListMap(listMap);
        return Response.ok(markedPaperMessage);
    }

    @Override
    public Response unPublishExamPaper(Integer paperId, Integer studentId) {
        ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(paperId, studentId);
        if (examEvaluation == null) {
            return Response.error(ResultCode.EXAM_NOT_FINISH_MARK_ERROR);
        }
        examEvaluation.setIsPublish(0);
        examEvaluationMapper.updateById(examEvaluation);
        return Response.ok();
    }

    //将试卷总分全部拉到100分
    public float getScorePropertyByPaperId(Integer paperId, Integer studentId){
        ExamPaper examPaper = examPaperMapper.selectById(paperId);
        ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(paperId, studentId);
        int FullScore = examPaper.getScore();
        int score = examEvaluation.getScore();
        return 100 * ((float) score / (float) FullScore);
    }

    @Override
    public Response getPaperRepetitionRate(Integer currentPaperId, Integer selectPaperId) {
        ExamPaper curExamPaper = examPaperMapper.selectById(currentPaperId);
        if (curExamPaper == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }
        ExamPaper selectExamPaper = examPaperMapper.selectById(selectPaperId);
        if (selectExamPaper == null){
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }

        List<Integer> curExamIssueIdList = examIssueMapper.getIssueListByPaperId(currentPaperId);
        List<Integer> selectExamIssueIdList = examIssueMapper.getIssueListByPaperId(selectPaperId);

        if (curExamIssueIdList.size() == 0){
            return Response.error(ResultCode.EXAM_NOT_HAVE_ISSUE_ERROR);
        }
        if (selectExamIssueIdList.size() == 0){
            return Response.error(ResultCode.EXAM_NOT_HAVE_ISSUE_ERROR);
        }

        ArrayList<Integer> notExists=new ArrayList(selectExamIssueIdList);
        ArrayList<Integer> exist=new ArrayList(selectExamIssueIdList);
        notExists.removeAll(curExamIssueIdList);
        exist.removeAll(notExists);

        float repetitionRate = (float) exist.size() / curExamIssueIdList.size();

        Map<String, Object> map = new HashMap<>();
        map.put("repetitionRate", (float)Math.round(repetitionRate * 100) / 100);
        map.put("repeatIssueIds", exist);
        return Response.ok(map);
    }

    @Override
    public Response updateExamPaperMessage(EvaluationUpdateVo evaluationUpdateVo) {
        ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(evaluationUpdateVo.getPaperId(), evaluationUpdateVo.getStudentId());
        if (examEvaluation == null){
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR);
        }

        examEvaluation.setMessage(evaluationUpdateVo.getMessage());
        examEvaluationMapper.updateById(examEvaluation);

        return Response.ok();
    }

    @Override
    public Response getPaperMessageList(Integer courseId) {
        Course course = courseMapper.selectById(courseId);
        List<ExamPaperListMessage> result = new ArrayList<>();

        if (course == null){
            return Response.ok(result);
        }

        List<ExamPaper> markedExamPaperList = examPaperMapper.getExamPaperByCourseId(courseId);

        for (ExamPaper examPaper : markedExamPaperList){
            result.add(new ExamPaperListMessage(examPaper));
        }

        return Response.ok(result);
    }

    @Override
    public Response getHistoryPaperList() {
        List<ExamPaper> examPaperList = examPaperMapper.getHistoryExamPaper();
        List<ExamPaperListMessage> result = new ArrayList<>();
        if (examPaperList.size() == 0){
            return Response.ok(result);
        }

        for (ExamPaper examPaper : examPaperList){
            result.add(new ExamPaperListMessage(examPaper));
        }

        return Response.ok(result);
    }

    @Override
    public Response getMarkedPaperMessageList(Integer courseId) {
        Course course = courseMapper.selectById(courseId);
        List<ExamPaperListMessage> result = new ArrayList<>();

        if (course == null){
            return Response.ok(result);
        }

        List<ExamPaper> markedExamPaperList = examPaperMapper.getMarkedExamPaperByCourseId(courseId);

        for (ExamPaper examPaper : markedExamPaperList){
            result.add(new ExamPaperListMessage(examPaper));
        }

        return Response.ok(result);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateExamPaper() {
        List<ExamPaper> examPaperList = examPaperMapper.updateExamPaper(LocalDateTime.now());
        for (int i = 0; i < examPaperList.size(); i++){
            examService.finishExam(examPaperList.get(i));
        }
    }

    @Override
    public Response finishExamByTeacher(int paperId) throws ParseException {
        ExamPaper examPaper = examPaperMapper.selectById(paperId);
        if(examPaper == null) {
            return Response.error(ResultCode.EXAM_EXIST_ERROR);
        }
        if(examPaper.getIsPublish() == 0){
            return Response.error(ResultCode.EXAM_NOT_PUBLISH_ERROR);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date currentDate = sdf.parse(sdf.format(new Date()));
        if(currentDate.compareTo(examPaper.getEndTime()) < 0){
            return Response.error(ResultCode.EXAM_NOT_FINISH_ERROR);
        }
        try{
            examService.finishExam(examPaper);
            return Response.ok();
        }catch (Exception e){
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR);
        }
    }

    @Override
    public Map<String, Integer> getPaperDifferentIssueTypeScoreSum(int paperId) {
        List<ExamIssue> examIssues = examIssueMapper.getExamIssueByPaperId(paperId);
        Map<String,Integer> result = new HashMap<>();
        for(ExamIssue examIssue : examIssues){
            Issue issue = issueMapper.getIssueMessageById(examIssue.getIssueId());
            result.put(issue.getIssueType(),result.getOrDefault(issue.getIssueType() , 0)+examIssue.getScore());
        }
        return result;
    }

    @Override
    public Response forecastScore(int paperId) {
        Map<String,Integer> paperIssue = getPaperDifferentIssueTypeScoreSum(paperId);
        ExamPaper examPaper = examPaperMapper.selectById(paperId);

        //指标一：学生能力雷达图
        Map<String,Double> studentRadar = issueRecordService.getStudentRadar(examPaper.getCourseId());

        //指标二：登陆学习次数
        Integer loginScore = this.getLoginScore();

        //指标三：前置课程分数
        List<PreCourseResponse> preCourseResponses = preCourseScoreService.getStudentPreCourseScore(MyHandlerInterceptor.getUid(),examPaper.getCourseId());

        double preCourseScore = 0.0;
        double paperScore = 0.0;
        double result = 0.0;
        for(PreCourseResponse preCourseResponse : preCourseResponses){
            preCourseScore = preCourseScore + preCourseResponse.getScore();
        }
        preCourseScore = preCourseScore/preCourseResponses.size();

        Set<String> keySet = paperIssue.keySet();
        for(String s : keySet){
            paperScore = paperScore + paperIssue.get(s)*studentRadar.get(s);
        }
        result = (loginScore + 20 * preCourseScore / 100 + 70 * paperScore / examPaper.getScore()) / 100 * examPaper.getScore();
        Map<String,Double> map = new HashMap<>();
        map.put("result",result);
        return Response.ok(map);
    }
    @Override
    public Integer getLoginScore() {
        int count = userMapper.getUserLoginCount(MyHandlerInterceptor.getUid());
        if((count>=0) && (count<20)) {
            return 5;
        } else if((count>=20) && (count< 40)) {
            return 6;
        } else if((count>=40) && (count< 60)) {
            return 7;
        } else if((count>=60) && (count< 80)) {
            return 8;
        } else if((count>=80) && (count< 100)) {
            return 9;
        } else {
            return 10;
        }
    }
}